package org.sanguine.tests.tenderpro.sax;

import com.sun.org.apache.xml.internal.utils.DefaultErrorHandler;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * Author: Alexey Kuznetsov
 * Date: 20.02.14
 * SVN $Id$
 */
public class DOMXMLWorker {
    private final static String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    private final static String W3C_XML_SCHEMA = XMLConstants.W3C_XML_SCHEMA_NS_URI;

    private File xmlFile;
    private String element;
    private boolean usingSchema;
    private DocumentBuilder builder;
    private Document doc;
    private XPath xpath;

    public DOMXMLWorker(String fileName, boolean schemaMode, String element) throws XMLStreamException, ParserConfigurationException, IOException, SAXException {
        xmlFile = new File(fileName);
        if (xmlFile.isFile()) {
            if (element != null) this.element = element.trim();
            else this.element = "";
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setValidating(true);
            if (schemaMode) {
                usingSchema = schemaMode;
                factory.setNamespaceAware(true);
                factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
            }
            factory.setIgnoringElementContentWhitespace(true);
            builder = factory.newDocumentBuilder();
            builder.setErrorHandler(new DefaultErrorHandler(true));
            XPathFactory xPathFactory = XPathFactory.newInstance();
            xpath = xPathFactory.newXPath();
            doc = builder.parse(xmlFile);
            if (element != null) this.element = element.trim();
        } else {
            throw new XMLStreamException("XML input file not found: " + fileName);
        }
    }

    public DOMXMLWorker(String fileName, boolean usingSchema) throws ParserConfigurationException, IOException, SAXException, XMLStreamException {
        this(fileName, usingSchema, null);
    }

    public DOMXMLWorker(String fileName) throws XMLStreamException, IOException, SAXException, ParserConfigurationException {
        this(fileName, false, null);
    }

    public void setElement(String anElement) {
        if (anElement != null) this.element = anElement.trim();
        else this.element = "";
    }

    public String getElement() {
        return element;
    }

    public int doCountElement() {
        if (element == null || element.isEmpty()) return -1;

        String path = "count(//" + element + ")";
        int c = -1;
        try {
            c = ((Number)xpath.evaluate(path, doc, XPathConstants.NUMBER)).intValue();
        } catch (XPathExpressionException e) {
            System.err.println("XPath expression '" + path + "' cannot be evaluated");
            e.printStackTrace();
        }

        return c;
    }

    /**
     * Select element in XML by key value equal Element setting and return value of Value element
     *
     * @param prefixPath - prefix XPath
     * @param keyElement - name of Key element
     * @param valueElement - name of Value element
     * @return - Found value or null
     */


    public String getChildValueForElement(String prefixPath, String keyElement, String valueElement) {
        if (prefixPath == null || prefixPath.isEmpty()) return null;
        if (keyElement == null || keyElement.isEmpty()) return null;
        if (valueElement == null || valueElement.isEmpty()) return null;

        String path = prefixPath.concat("/").concat(keyElement).concat("[text()=\"").concat(getElement()).concat("\"]");
        NodeList nodes;
        try {
            nodes = (NodeList)xpath.evaluate(path, doc, XPathConstants.NODESET);
        } catch (XPathExpressionException e) {
            System.err.println("XPath expression '" + path + "' cannot be evaluated");
            e.printStackTrace();
            return null;
        }
        if (nodes != null && nodes.getLength() > 0) {
            NodeList actionNodeList = nodes.item(0).getParentNode().getChildNodes();
            for (int i=0; i < actionNodeList.getLength(); i++) {
                if (actionNodeList.item(i).getLocalName().equals(valueElement)) return actionNodeList.item(i).getTextContent();
            }
        }
        return null;
    }
}
